﻿using DocumentFormat.OpenXml.Lite.Core.Office;
using DocumentFormat.OpenXml.Lite.Shared;
using DocumentFormat.OpenXml.Lite.Helper;
using DocumentFormat.OpenXml.Lite.Xml;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using DocumentFormat.OpenXml.Lite.WordprocessingML.Word.SectionProperties;
using DocumentFormat.OpenXml.Lite.Core;
using DocumentFormat.OpenXml.Lite.Core.Interfaces;

namespace DocumentFormat.OpenXml.Lite.WordprocessingML.Word.Base
{
    [XmlRoot("body", Namespace = Constants.WordMain)]
    public class Body : XmlSerializable, ISectionPropertyContainer
    {
        [XmlIgnore]
        public Guid DocumentId { get; set; }

        [Optional]
        [XmlElement("", Namespace = Constants.WordMain)]
        public XmlList<IOfficeElement> Elements { get; set; }

        [Optional]
        [XmlElement("sectPr", Namespace = Constants.WordMain)]
        public SectionProperty SectionProperties { get; set; }

        public Body()
        {
            Elements = new XmlList<IOfficeElement>();
            Elements.Changing += Elements_Changing;
        }

        #region Methods

        public Paragraph AddParagraph()
        {
            Paragraph p = new Paragraph();
            p.DocumentId = this.DocumentId;
            Elements.Add(p);
            return p;
        }

        public Table.Table AddTable()
        {
            Table.Table t = new Table.Table();
            t.DocumentId = this.DocumentId;
            Elements.Add(t);
            return t;
        }

        public Table.Table AddTable(int columns, int rows)
        {
            Table.Table t = new Table.Table(columns, rows);
            t.DocumentId = this.DocumentId;
            Elements.Add(t);
            return t;
        }

        /// <summary>
        /// Hint: you cannot add two elements with the same type.
        /// </summary>
        /// <param name="element"></param>
        /// <returns>True, if the list not contains element with the same type. 
        /// False otherwise (in this case the content will be override the old one).</returns>
        public bool AddSectionProperty(ISectionPropElement element)
        {
            if (SectionProperties == null)
            {
                SectionProperties = new SectionProperty();
            }

            if (element is HeaderReference ||
                 element is FooterReference ||
                 element is PrinterSettings)
            {
                (DocumentManager.Instance.FindDocument(DocumentId) as WordDocument).Document
                    .AddNamespace(Constants.GetDefaultPrefix(Constants.Relationship), Constants.Relationship);
            }

            var obj = SectionProperties.Elements.FirstOrDefault(e => e.GetType() == element.GetType());
            if (obj != null)
            {
                (obj as ISectionPropElement).Copy(element);
            }
            else
            {
                SectionProperties.Elements.Add(element);
                return true;
            }

            return false;
        }

        #endregion

        #region Events

        void Elements_Changing(object sender, ListEventArgs<IOfficeElement> args)
        {
            if (args.Type == ListEventType.Remove)
                return;

            foreach (var p in args.Objects)
            {
                p.DocumentId = this.DocumentId;
            }
        }

        #endregion
    }
}
